#pragma once
#include <iostream>
#include <functional>
#include <string>
#include "tcp_server.hpp"

/*代码整体注释：
    1.首先该模块代码是为了封装套接字，把一个网络连接设计为一个类
    2.在这个类中，我们可以对套接字衍生的变量进行操作，例如输入、输出缓冲区，客户端信息
    3.设计工厂模式，我们通过外部就能够建立连接*/

class Connection;
class TcpServer;
using func_t = std::function<void(Connection *)>;

class Connection
{
public:

    Connection(int sock_fd, uint32_t events, TcpServer *R) : _sock_fd(sock_fd), _events(events), _R(R) {}
    ~Connection() {}

    int GetSockFd() const { return _sock_fd; }
    uint32_t GetEvents() const { return _events; }

    // 外部进行函数的注册
    void RegisterFunc(func_t recver, func_t sender, func_t excepter)
    {
        _recv_func = recver;
        _send_func = sender;
        _except_func = excepter;
    }
    void SetClient(const struct sockaddr_in c)  // 从网络中获取的信息
    {
        _client = c;
    }
    void SetEvents(uint32_t events)
    {
        _events = events;
    }
    void AddInbuffer(const std::string &inbuffer)   // 将读到的数据写入输入缓冲区中
    {
        _in_buffer += inbuffer;
    }
    void AddOutbuffer(const std::string &outbuffer) // 准备好待发送的数据到输出缓冲区中
    {
        _out_buffer += outbuffer;
    }
    std::string &GetInBuffer()  // 通过引用可以便于外部的引用变量进行寻址
    {
        return _in_buffer;
    }
    std::string &GetOutBuffer()  // 通过引用可以便于外部的引用变量进行寻址
    {
        return _out_buffer;
    }
    bool OutBufferEmpty()
    {
        return !_out_buffer.empty(); // 不为空进行发送
    }

private:
    int _sock_fd;
    std::string _in_buffer;
    std::string _out_buffer;

    // 关心的事件
    uint32_t _events;
    // 对于一个链接维护一个client信息
    struct sockaddr_in _client;

public:
    // 对特定connection进行处理的回调函数
    func_t _recv_func;
    func_t _send_func;
    func_t _except_func;

    // 指回TCP服务器的指针，执行事件处理
    TcpServer *_R;
};

// 设计模式：工厂模式，构建Connection
class ConnectionFactory
{
public:
    // Epoll模型在TCP中需要分开监听套接字和普通套接字
    static Connection *BulidListenConnection(int listen_fd, func_t recver, uint32_t events, TcpServer *R)
    {
        Connection *conn = new Connection(listen_fd, events, R);
        conn->RegisterFunc(recver, nullptr, nullptr);
        return conn;
    }
    static Connection *BulidSockConnection(int sock_fd, func_t recver, func_t sender, func_t excepter, uint32_t events, TcpServer *R)
    {
        Connection *conn = new Connection(sock_fd, events, R);
        conn->RegisterFunc(recver, sender, excepter);
        return conn;
    }

private:
};
